﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using EnvDTE;
using System.ComponentModel;
using Microsoft.Web.Administration;

namespace none.Prada
{
    /// <summary>
    /// Interaction logic for MyControl.xaml
    /// </summary>
    public partial class MyControl : UserControl
    {

        #region Properties
        [DefaultValue(-1)]
        public Int32 SelectedProcessId { get; set; }
        public List<Int32> SelectedProcessIds { get; set; }

        public Dictionary<Int32, Process> DebugProcesses { get; set; }

        private ApplicationPoolCollection _appPools;

        public ApplicationPoolCollection AppPools
        {
            get
            {
                //It is necessary to instantiate the ServerManager at every call, since otherwise procs after an iisreset cannot be caught
                ServerManager manager = new ServerManager();
                return manager.ApplicationPools;
            }
        }


        #endregion

        public MyControl()
        {
            InitializeComponent();
            FillApplicationPools();
            FillIdentities();
            SelectedProcessIds = new List<Int32>();
            LibProcesses.SelectedItems.Clear();
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions")]
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(string.Format(System.Globalization.CultureInfo.CurrentUICulture, "We are inside {0}.button1_Click()", this.ToString()),
                            "WADA W3WP Advanced Attacher");

        }

        protected void AttachCurrentProcesses()
        {
            if (SelectedProcessIds == null)
                SelectedProcessIds = new List<Int32>();
            if (SelectedProcessIds.Count > 0)
            {
                foreach (Int32 processId in SelectedProcessIds)
                {
                    Process pSelected = null;
                    if (DebugProcesses.TryGetValue(processId, out pSelected))
                    {
                        pSelected.Attach();
                        PradaPackage.dte.Debugger.CurrentProcess = pSelected;
                    }
                }
            }
        }

        private void BtnAttachProcess_Click(object sender, RoutedEventArgs e)
        {
            if (LibProcesses.SelectedItems != null)
            {
                AttachCurrentProcesses();
            }
        }


        private void BtnGetProcesses_Click(object sender, RoutedEventArgs e)
        {
            PopulateProcessList();
        }

        private void PopulateProcessList()
        {
            LibProcesses.Items.Clear();
            DebugProcesses = new Dictionary<Int32, Process>();

            Dictionary<Process, System.Diagnostics.Process> processes = W3WPProcessLister.GetMatchedProcesses(PradaPackage.dte, CkbOnlyW3WP.IsChecked.Value);
            List<System.Diagnostics.Process> sysProcesses = new List<System.Diagnostics.Process>();
            for (int i = 0; i < processes.Count; i++)
            {
                System.Diagnostics.Process p = processes.Values.ElementAt<System.Diagnostics.Process>(i);
                Process pDebug = processes.Keys.ElementAt<Process>(i);
                try
                {
                    if (p != null && p.Responding && !p.HasExited)
                    {
                        if (CmbApplicationPools.SelectedIndex > 0)
                        {
                            object selectedPool = CmbApplicationPools.SelectedItem;
                            if (selectedPool != null)
                            {
                                try
                                {
                                    String SelectedAppPool = (((ComboBoxItem)selectedPool).Uid).ToString();
                                    if (BelongsToAppPool(SelectedAppPool, p.Id))
                                    {
                                        sysProcesses.Add(p);
                                        DebugProcesses.Add(pDebug.ProcessID, pDebug);
                                        LibProcesses.Items.Add(new ListBoxItem() { Uid = p.Id.ToString(), Content = GetProcessDescription(p, pDebug) });
                                    }
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show(string.Format(System.Globalization.CultureInfo.CurrentUICulture, ex.Message + " " + ex.StackTrace, this.ToString()),
                            "WADA Exception");
                                }

                            }
                        }
                        else if (CmbIdentities.SelectedIndex > 0)
                        {
                            object selectedIdentity = CmbIdentities.SelectedItem;
                            if (selectedIdentity != null)
                            {
                                try
                                {
                                    String SelectedIdentyName = (((ComboBoxItem)selectedIdentity).Uid).ToString();
                                    if (BelongsToIdentity(SelectedIdentyName, p.Id))
                                    {
                                        sysProcesses.Add(p);
                                        DebugProcesses.Add(pDebug.ProcessID, pDebug);
                                        LibProcesses.Items.Add(new ListBoxItem() { Uid = p.Id.ToString(), Content = GetProcessDescription(p, pDebug) });
                                    }
                                }
                                catch (Exception ex)
                                {

                                    MessageBox.Show(string.Format(System.Globalization.CultureInfo.CurrentUICulture, ex.Message + " " + ex.StackTrace, this.ToString()),
                            "WADA Exception");                                    
                                }
                            }
                        }
                        else
                        {
                            sysProcesses.Add(p);
                            DebugProcesses.Add(pDebug.ProcessID, pDebug);
                            LibProcesses.Items.Add(new ListBoxItem() { Uid = p.Id.ToString(), Content = GetProcessDescription(p, pDebug) });
                        }
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show(string.Format(System.Globalization.CultureInfo.CurrentUICulture, e.Message + " " + e.StackTrace, this.ToString()),
                                "WADA Exception");
                    continue;
                }
            }
        }

        private String GetProcessDescription(System.Diagnostics.Process process, Process processDebug)
        {
            String appendix = (CkbOnlyW3WP.IsChecked.Value) ? GetMatchingApplicationPoolInfo(process.Id) : String.Empty;
            return "(" + process.Id + ") " + process.ProcessName + " / " + process.MainWindowTitle + " " + appendix;
        }

        private void LibProcesses_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (SelectedProcessIds == null)
                SelectedProcessIds = new List<Int32>();
            if (LibProcesses.SelectedItem != null)
            {
                //This will become obsolete
                SelectedProcessId = Int32.Parse((((ListBoxItem)LibProcesses.SelectedItem).Uid));
                //...and replaced by this:
                foreach (ListBoxItem item in LibProcesses.SelectedItems)
                {
                    SelectedProcessIds.Add(Int32.Parse(item.Uid));
                }
            }
            else
            {
                SelectedProcessId = -1;
            }
        }

        private String GetMatchingApplicationPoolInfo(Int32 ProcessId)
        {

            foreach (ApplicationPool pool in AppPools)
            {
                foreach (WorkerProcess wp in pool.WorkerProcesses)
                {
                    if (wp.ProcessId == ProcessId)
                    {
                        return pool.Name;
                    }
                }
            }
            return String.Empty;
        }

        private Boolean BelongsToAppPool(String appPoolName, Int32 processId)
        {
            ApplicationPool pool = Get(appPoolName);
            if (pool != null)
            {
                foreach (WorkerProcess wp in pool.WorkerProcesses)
                {
                    if (wp.ProcessId == processId)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        private Boolean BelongsToIdentity(String userName, Int32 processID)
        {
            foreach (ApplicationPool pool in AppPools)
            {
                foreach (WorkerProcess process in pool.WorkerProcesses)
                {
                    if (pool.ProcessModel != null && !String.IsNullOrEmpty(pool.ProcessModel.UserName) && !String.IsNullOrEmpty(userName))
                    {
                        if (pool.ProcessModel.UserName.ToLower() == userName.ToLower() && process.ProcessId == processID)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        private ApplicationPool Get(String name)
        {
            foreach (ApplicationPool pool in AppPools)
            {
                if (!String.IsNullOrEmpty(name))
                {
                    if (pool.Name.ToLower() == name.ToLower())
                    {
                        return pool;
                    }
                }
            }
            return null;
        }

        public void FillApplicationPools()
        {
            CmbApplicationPools.Items.Clear();
            CmbApplicationPools.Items.Add(new ComboBoxItem() { Uid = "", Content = "" });
            foreach (ApplicationPool pool in AppPools)
            {
                CmbApplicationPools.Items.Add(new ComboBoxItem() { Uid = pool.Name, Content = pool.Name });
            }
        }

        public void FillIdentities()
        {
            CmbIdentities.Items.Clear();
            CmbIdentities.Items.Add(new ComboBoxItem() { Uid = "", Content = "" });
            HashSet<String> userNames = new HashSet<String>();
            foreach (ApplicationPool pool in AppPools)
            {
                try
                {
                    if (pool.ProcessModel != null)
                    {
                        userNames.Add(pool.ProcessModel.UserName.ToLower());
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format(System.Globalization.CultureInfo.CurrentUICulture, ex.Message + " " + ex.StackTrace, this.ToString()),
                            "WADA Exception");
                }
            }

            foreach (String userName in userNames)
            {
                if (!String.IsNullOrWhiteSpace(userName) && !String.IsNullOrEmpty(userName))
                    CmbIdentities.Items.Add(new ComboBoxItem() { Uid = userName, Content = userName });
            }
        }

        private void CmbApplicationPools_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (CmbApplicationPools.SelectedIndex > 0)
            {
                CmbIdentities.SelectedIndex = 0;
            }
        }

        private void CmbIdentities_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (CmbIdentities.SelectedIndex > 0)
            {
                CmbApplicationPools.SelectedIndex = 0;
            }
        }

        public void ListBoxItem_MouseDoubleClick(object sender, RoutedEventArgs e)
        {
            if (LibProcesses.SelectedItems != null)
            {
                if (LibProcesses.SelectedItems.Count > 1)
                {
                    MessageBox.Show(string.Format(System.Globalization.CultureInfo.CurrentUICulture, "Please use the \"Attach\" button to attach multiple processes", this.ToString()),
                            "WADA Information");
                }
                else if (LibProcesses.SelectedItems.Count == 1)
                {
                    AttachCurrentProcesses();
                }
            }
        }
    }
}